﻿using System;
using System.Drawing;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Xml;
//using System.Xml.Serialization;
using OSM;

namespace OSMConvert
{
	partial class OSMConvert_Main
	{
		static OSMData Root = null;
		static List<ProgressEntry> Sources = new List<ProgressEntry>();

		static void LoadProgress()
		{
			string[] row = File.ReadAllLines("progress.txt");
			foreach (var r in row)
			{
				string[] fields = r.Split('\t');
				Sources.Add(new ProgressEntry(fields));
				//Console.WriteLine("Progress for " + fields[0]);
			}
		}
		static void SaveProgress()
		{
			List<string> buf = new List<string>();
			foreach (var r in Sources)
				buf.Add(r.ToString());
			File.WriteAllLines("progress.txt", buf.ToArray());
		}

		static void WriteBoolField(int C, bool val)
		{
			Console.CursorLeft = C;
			if (val)
			{
				Console.ForegroundColor = ConsoleColor.Green;
				Console.Write("   OK  ");
			}
			else
			{
				Console.ForegroundColor = ConsoleColor.Red;
				Console.Write("  N/A  ");
			}
			Console.ResetColor();
		}
		static void DrawTable()
		{
			Console.Clear();	
			foreach (var prg in Sources)
			{
				String Field1 = prg.Code.PadRight(10);
				String Field2 = "".PadRight(7);
				String Field3 = "".PadRight(7);
				Console.Write("|" + Field1 + "|" + Field2 + "|" + Field3 + "|");
				Console.CursorLeft = 12;
				WriteBoolField(12, prg.Indexed);
				WriteBoolField(20, prg.Converted);
				Console.WriteLine();
			}
		}
		static void DrawMenu()
		{
			DrawTable();
			Console.WriteLine("1. Index xml files");
			Console.WriteLine("2. Convert xml to binary format");
			Console.WriteLine("3. Extract administrative data from OSM");
			//Console.WriteLine("4. Plot admin points");
			//Console.WriteLine("4. Create Graph from admin areas only");
		}

		static void Main(string[] args)
		{
			if (File.Exists("progress.txt"))
			{
				LoadProgress();
				//Sources.Add(new ProgressEntry("SVN", "slovenia-latest.osm", DateTime.MinValue));
				//Sources.Add(new ProgressEntry("SVK", "slovakia-latest.osm", DateTime.MinValue));
				//Sources.Add(new ProgressEntry("CZE", "czech-republic-latest.osm", DateTime.MinValue));
			}
			else
			{
				Sources.Add(new ProgressEntry("LUX", "luxembourg-latest.osm", DateTime.MinValue));
				Sources.Add(new ProgressEntry("HUN", "hungary-latest.osm", DateTime.MinValue));
				Sources.Add(new ProgressEntry("AUT", "austria-latest.osm", DateTime.MinValue));
			}
			DrawMenu();

			const int NODE_HUNGARY = 249399347;
			const int REL_HUNGARY = 21335;

			ConsoleKey C = Console.ReadKey(true).Key;
			switch (C)
			{
					//Index XML files
				case ConsoleKey.D1:
				#region D1
					{
						foreach (var i in Sources)
						{
							Console.Write("Indexing " + i.Code + ": ");
							i.MakeIndex();
							SaveProgress();
						}
					}
					break;
					#endregion
				//Convert OSM into binary format
				#region D2
				case ConsoleKey.D2:
					{
						for (int i = 0; i < Sources.Count; i++)
						{
							if (Sources[i].MakeConvert(x =>
							{
								Console.SetCursorPosition(20, i * 2 + 1);
								Console.Write(" " + (x * 0.1).ToString("000.0") + "%");
							}))
							{
								string admindir = OSMCore.OSMPath + Sources[i].Code + "_admin";
								if (Directory.Exists(admindir))
									Directory.Delete(admindir, true);
							}
							SaveProgress();
							DrawTable();
						}
						Console.WriteLine("Converted");
						//DrawMenu();
					}
					break;
				#endregion
				//Extract administrative relations
				#region D3
				case ConsoleKey.D3:
					{
						for (int i = 0; i < Sources.Count; i++)
						{
							Sources[i].MakeAdmin(x =>
							{
								Console.SetCursorPosition(30, i);
								if (x == 0)
									Console.Write("Search");
								else if (x == 1)
									Console.Write(" Rels ");
								else if (x == 2)
									Console.Write(" Ways ");
								else if (x == 3)
									Console.Write("Nodes ");
								else if (x == 4)
									Console.Write(" DONE ");
							});
							SaveProgress();
							DrawTable();
						}
					}
					break;
				#endregion
#if xxx
					//Create country maps
				#region D4
				case ConsoleKey.D4:
					{
						Console.Clear();
						foreach (string s in Completed)
						{
							String FN = OSMCore.OSMPath + s + "_admin\\nodes.bin";
							MathDrawer D = new MathDrawer(2000, 2000);
							D.Set3G(17, 48.5, 0.001);

							FileInfo FI = new FileInfo(FN);
							Console.WriteLine(s + " (" + FI.Length + ")");
							BinaryReader R = new BinaryReader(File.OpenRead(FN));
							long N = FI.Length / 24;
							for (int i = 0; i < N; i++)
							{
								long ID = R.ReadInt64();
								double lng = R.ReadDouble();
								double ltd = R.ReadDouble();
								if (!double.Equals(lng, double.NaN))
									D.DrawPoint(new V3G(lng, ltd), 1);
							}
							R.Close();
							Console.WriteLine(DateTime.Now);
							D.BMP.Save(OSMCore.OSMPath + s + ".png");
							Console.WriteLine(s + " plotted");
						}
						DrawMenu();
						//TextWriter W = File.CreateText(OSMCore.OSMPath + "relations.txt");
						//W.Close();
					}
					break;
				#endregion
				case ConsoleKey.D5:
					{
						Console.Clear();
						OSMData D = new OSMData();
						Console.WriteLine("Merging...");
						foreach (string s in Completed)
						{
							if (Directory.Exists(OSMCore.OSMPath + s + "_admin"))
							{
								D.Merge(OSMCore.OSMPath + s + "_admin\\");
								Console.WriteLine(s);
							}
							else
								Console.WriteLine(s + " skipped");
						}
						D.Save("C:\\OSMData\\EU_admin\\");
						Console.WriteLine("Merged");
					}
					break;
				case ConsoleKey.D5:
					{
						Console.Clear();
						string s = "EU";
						{
							String FN = OSMCore.OSMPath + s + "_admin\\nodes.bin";
							MathDrawer D = new MathDrawer(2000, 2000);
							D.Set3G(17, 48.5, 0.001);

							FileInfo FI = new FileInfo(FN);
							Console.WriteLine(s + " (" + FI.Length + ")");
							BinaryReader R = new BinaryReader(File.OpenRead(FN));
							long N = FI.Length / 24;
							for (int i = 0; i < N; i++)
							{
								long ID = R.ReadInt64();
								double lng = R.ReadDouble();
								double ltd = R.ReadDouble();
								if (!double.Equals(lng, double.NaN))
									D.DrawPoint(new V3G(lng, ltd), 1);
							}
							R.Close();
							Console.WriteLine(DateTime.Now);
							D.BMP.Save(OSMCore.OSMPath + s + ".png");
							Console.WriteLine(s + " plotted");
						}
						DrawMenu();
					}
					break;
				case ConsoleKey.D6:
					{
						OSMData D = new OSMData();
						D.Load("C:\\OSMData\\AUT_admin\\");
						var X = D.RelID[16239];
						X.MakeBorderR("");
						Console.WriteLine("Done");
						int L = -1;
						{
							foreach (OSMRelation R in D.RelID.Values)
							{
								if (R["type"] != "multilinestring" && R["boundary"] == "administrative" && R["admin_level"] == L.ToString())
								{
									Console.WriteLine(R["name"]);

									R.MakeBorder();
								}
							}
						}
					}
					break;
				case ConsoleKey.D7:
					{
						OSMData D = new OSMData();
						D.Load("C:\\OSMData\\EU_admin\\");

						OSMRelation[] X = { D.RelID[21335], D.RelID[16239], D.RelID[14296] };

						foreach (var x in X)
							x.MakeBorderR("");
						Dictionary<int, List<OSMRelation>> levels = new Dictionary<int, List<OSMRelation>>();
						for (int i = 2; i < 12; i++)
							levels.Add(i, new List<OSMRelation>());

						Action<OSMRelation> Take = null;
						Take = crnt =>
						{
							int l;
							if (int.TryParse(crnt["admin_level"], out l))
							{
								levels[l].Add(crnt);
								foreach (var sub in crnt.Subareas)
									Take(sub);
							}
						};

						foreach (var x in X)
							Take(x);
						for (int i = 2; i < 12; i++)
						{
							MathDrawer G = new MathDrawer(2000, 2000);
							G.Set3G(17, 48.5, 0.001);
							foreach (var sub in levels[i])
								foreach (var w in sub.Members)
								{
									if (w.RefObj is OSMWay)
									{
										var W = w.RefObj as OSMWay;
										foreach (OSMNode N in W.NodeObj)
											if (sub.hasborder)
												G.DrawPoint(new V3G(N.Longit, N.Latit), 1, Color.Black);
											else
												G.DrawPoint(new V3G(N.Longit, N.Latit), 1, Color.Red);
									}
								}
							G.BMP.Save("Level_" + i + ".png");
							Console.WriteLine("Level " + i + " plotted");
						}
					}
					break;
#endif
				default:
					break;
			}
			Console.ReadKey(true);
		}
		static void Extract(OSMRelation r, ref OSMData d)
		{
			d.AddRegionR(r);
			if (r.admin_centre != null)
				d.AddNodeR(r.admin_centre);
			else
			{
				Console.WriteLine("Region #" + r.ID + "(" + r["name"] + ") has no center!");
			}
			if (r.Subareas != null)
				foreach (var x in r.Subareas)
					Extract(x, ref d);
		}
		static void Convert(String FN, ref OSMData D)
		{
			Dictionary<String, int> LineNumbers = new Dictionary<String, int>();
			int N = 0;
			if (false)
			{
				TextReader R = File.OpenText(FN);
				while (R.ReadLine() != null)
					N++;
			}
			else
				N = 18030391;
			Console.WriteLine(N + " Rows");
			OSMData.ConvertOSM("",FN, FN, "XXX", n =>
			{
				Console.SetCursorPosition(0, 2);
				Console.WriteLine(n[0].ToString().PadLeft(8));
				Console.WriteLine(n[1] + " Nodes");
				Console.WriteLine(n[2] + " Ways");
				Console.WriteLine(n[3] + " Relations");
			});
			Console.WriteLine("Saving output...");
			D.Save("C:\\OSMData\\hun\\");
			Console.WriteLine("Saved");
		}
	}
}